using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Drawing2D;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using PaxScript.Net;
using System.Text.RegularExpressions;

namespace stateHepek
{
    public partial class Form1 : Form
    {
        // globalne
        int tool;           // koji tool koristimo iz izbornika
        bool miceSe;        // da li micemo node
        Point loc;          // locakciaj nodea azdnja
        public  ArrayList nodes;    // svi cvorovi kreirani
        public static state pocetni;     // ime pocetnog statea
        public static ArrayList krajnji;  // imena krajnjih stateova
        state privLink;
        public ArrayList veze;
        public static string scriptCode;
        public static PaxScripter skripta;
        private PaxScripter paxScripter1;
        private System.ComponentModel.IContainer komp;
        Image zaPrint;
        Point[] markiraniLink;
        veza markiranaVeza;
        state contextSender;
        public static Form1 forma;
        

        public class state : Button
        {
            public string ime;
            
            public state(int i)
            {
                ime = "q" + i.ToString();
            }
        }


        public void skripta_OnChangeState(PaxScript.Net.PaxScripter sender, PaxScript.Net.ChangeStateEventArgs e)
        {
            if (e.NewState == ScripterState.Error)
            {
                foreach (ScriptError err in skripta.Error_List)
                    MessageBox.Show("Error: " + err.Message);
            }
            else if (e.OldState == ScripterState.Init)
            {
                skripta.AddModule("1");
                skripta.AddCode("1", scriptCode);
            }
        }


        private class veza 
        {
            public state p, k;
            public string funkcija;
            public veza(state poc, state kraj,string f)
            {
                p = poc;
                k = kraj;
                funkcija = f;
            }
        }

        public static bool TackaPoligon(Point p, Point[] poly)
        {
            Point p1, p2;
            bool inside = false;

            if (poly.Length < 3)
                return inside;

            Point oldPoint = new Point(poly[poly.Length - 1].X, poly[poly.Length - 1].Y);

            for (int i = 0; i < poly.Length; i++)
            {
                Point newPoint = new Point(poly[i].X, poly[i].Y);

                if (newPoint.X > oldPoint.X)
                {
                    p1 = oldPoint;
                    p2 = newPoint;
                }
                else
                {
                    p1 = newPoint;
                    p2 = oldPoint;
                }


                if ((newPoint.X < p.X) == (p.X <= oldPoint.X)
                    && ((long)p.Y - (long)p1.Y) * (long)(p2.X - p1.X)
                     < ((long)p2.Y - (long)p1.Y) * (long)(p.X - p1.X))
                {
                    inside = !inside;
                }

                oldPoint = newPoint;
            }

            return inside;
        }

        public void pobrisiEkran()
        {
            podloga.Controls.Clear();
            nodes.Clear();
            veze.Clear();
            tabela.Rows.Clear();
            tabela.Columns.Clear();
            konzola.Text = ulaz.Text = "";
            ispis.Expanded = false;
            tool = 0;
        }

        public void preCrtaj()
        {
            podloga.Refresh();
             Graphics G = podloga.CreateGraphics();
            G.Clear(Color.White);
            G.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            foreach (veza v in veze)
            {
                float px = v.p.Location.X, py = v.p.Location.Y;
                float kx = v.k.Location.X, ky = v.k.Location.Y;
                if (v.p == v.k)
                {
                    G.DrawLine(new Pen(Color.Black, 1.6f), px +15, py , px +5, py - 20);
                    G.DrawLine(new Pen(Color.Black, 1.6f), px + 5, py-20, px + 40, py - 20);
                    G.DrawLine(new Pen(Color.Black, 1.6f), px + 40, py - 20, px +30, py);
                    string[] linije = v.funkcija.Split('\n');
                        foreach ( string p in linije)
                            py -= 10;
                    G.DrawString(v.funkcija, new Font("Tahoma", 8), Brushes.Red, new PointF(px +6,py-30));
                }
                else
                {
                    PointF lok = new PointF();
                    G.DrawLine(new Pen(Color.Black, 1.6f), px + 22, py + 22, kx + 22, ky + 22);
                    if (px > kx) lok.X = kx + ((px - kx) / 2f); else lok.X = px + ((kx - px) / 2f);
                    if (py > ky) lok.Y = ky + ((py - ky) / 2f); else lok.Y = py + ((ky - py) / 2f);
                    G.DrawString(v.funkcija, new Font("Tahoma", 8), Brushes.Red, lok);
                }
                if (markiraniLink != null)
                {
                    Pen selek = new Pen(Color.LightSlateGray, 1);
                    selek.DashStyle = DashStyle.Dash;
                    G.DrawPolygon(selek, markiraniLink);
                }

            }
         }

        public state dodajState(int x,int y)
        {
            state novi = new state(nodes.Count + 1);
            podloga.Controls.Add(novi);

            novi.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
            novi.ContextMenuStrip = this.izbornik;
            novi.FlatAppearance.BorderSize = 0;
            novi.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            novi.ForeColor = System.Drawing.SystemColors.ActiveCaption;
            novi.Image = global::stateHepek.Properties.Resources.state;
            novi.Location = new System.Drawing.Point(46, 46);
            novi.Name = novi.ime;
            novi.Size = new System.Drawing.Size(47, 47);
            novi.TabIndex = 0;
            novi.Text = novi.ime;
            novi.UseVisualStyleBackColor = true;
            novi.MouseMove += new System.Windows.Forms.MouseEventHandler(sMouseMove);
            novi.MouseDown += new System.Windows.Forms.MouseEventHandler(sMouseDown);
            novi.MouseUp += new System.Windows.Forms.MouseEventHandler(sMouseUp);
            novi.MouseClick += new System.Windows.Forms.MouseEventHandler(sMouseClick);
            novi.Location = new Point(x - 20, y - 20);
            nodes.Add(novi);
            if (pocetni == null)
            {
                pocetni = novi;
                pocetni.Image = global::stateHepek.Properties.Resources.pocetni;
            }
            return novi;
        }

        public void dodajVezu(state alice, state bob,string s)
        {
            veze.Add(new veza(alice, bob, s));
        }


        private void paxScripter1_OnChangeState(PaxScript.Net.PaxScripter sender, PaxScript.Net.ChangeStateEventArgs e)
        {
            if (e.NewState == ScripterState.Error)
            {
                foreach (ScriptError err in paxScripter1.Error_List)
                    MessageBox.Show("Error: " + err.Message);
            }
            else if (e.OldState == ScripterState.Init)
            {
                paxScripter1.RegisterInstance("forma", this);
                paxScripter1.RegisterType(typeof(ArrayList));
                paxScripter1.RegisterType(typeof(veza));
                paxScripter1.RegisterType(typeof(state));
                
                paxScripter1.AddModule("1");
                paxScripter1.AddCode("1", scriptCode);
            }

        }

        public Form1()
        {
            InitializeComponent();
            tool = 0;       // move je defaultni tool
            nodes = new ArrayList();
            veze = new ArrayList();
            krajnji = new ArrayList();
            markiraniLink = null;
            pocetni = null;


            paxScripter1 = new PaxScripter(komp);
            paxScripter1.DefaultInstanceMethods = false;
            paxScripter1.State = ScripterState.Init;
            paxScripter1.OnChangeState += new PaxScript.Net.ChangeStateHandler(paxScripter1_OnChangeState);

        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void sMouseDown(object sender, MouseEventArgs e)
        {
            state priv = sender as state;
            if (e.Button == MouseButtons.Right)
                contextSender = priv;
            switch (tool) {
                case 0:
                case 1:
                    miceSe = true;
                    loc = priv.Location;

                    break;
                case 2:
                    priv.Image = global::stateHepek.Properties.Resources.selekt;
                    privLink = priv;
                    tool = 3; // selektovali smo jedan sad cemo i drugi :)
                    break;
                case 3:
                    // trazi unos funkcije prelaza
                    VezaVar f2 = new VezaVar();
                    string funk="";
                    if (f2.ShowDialog() == DialogResult.OK)
                        funk = f2.funkcije.Text;

                    // dodaj vezu u veze :)
                    dodajVezu(privLink, priv, funk);
                    preCrtaj();

                    privLink.Image = global::stateHepek.Properties.Resources.state;
                    if (privLink == pocetni)
                        privLink.Image = global::stateHepek.Properties.Resources.pocetni;
                    foreach (state s in krajnji)
                        s.Image = global::stateHepek.Properties.Resources.kraj;
                    // prebaci na select tool
                    toolMici_Click(sender, null);
                    break;
            }
        }

        private void sMouseMove(object sender, MouseEventArgs e)
        {
            if (true == miceSe)
            {
                markiraniLink = null;
                preCrtaj();
                state priv = sender as state;
                priv.Left = priv.Left + e.Location.X - 20;
                priv.Top = priv.Top + e.Location.Y - 20;
            }
        }

        private void sMouseUp(object sender, MouseEventArgs e)
        {
            miceSe = false;
        }
        private void sMouseClick(object sender, MouseEventArgs e)
        {

        }

        private void dodajState_Click(object sender, EventArgs e)
        {


        }

        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            if (tool == 1)
            {
                state priv = dodajState(e.Location.X, e.Location.Y);
            }
        }

        private void toolMici_Click(object sender, EventArgs e)
        {
            tool = 0;
            toolNoviState.Checked = false;
            toolMici.Checked = true;
            toolPovezi.Checked = false;
        }

        private void toolNoviState_Click(object sender, EventArgs e)
        {
            tool = 1;
            toolNoviState.Checked = true;
            toolMici.Checked = false;
            toolPovezi.Checked = false;
        }

        private void toolPovezi_Click(object sender, EventArgs e)
        {
            toolPovezi.Checked = true;
            toolNoviState.Checked = false;
            toolMici.Checked = false;
            tool = 2;
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            preCrtaj();
        }

        private void toolMove_Click(object sender, EventArgs e)
        {

        }

        private void pocetniToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (pocetni != null)
                pocetni.Image = global::stateHepek.Properties.Resources.state;
            foreach (state s in krajnji.ToArray())
                if (s == contextSender)
                    krajnji.Remove(contextSender);
            pocetni = contextSender;
            pocetni.Image = global::stateHepek.Properties.Resources.pocetni;
            
            
        }

        private void krajToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (contextSender == pocetni)
                pocetni = null;
            krajnji.Add(contextSender);
            contextSender.Image = global::stateHepek.Properties.Resources.kraj;
        }

        private void noviProjekatToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("If you continue the current data will be lost!\nAre you shure?", "Are you shure?", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning)
            == DialogResult.Cancel)
                return;
            pobrisiEkran();
            preCrtaj();
        }

        private void spasiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog spasiDialog = new SaveFileDialog();
            spasiDialog.Title = "Spasi State file";
            spasiDialog.Filter = "State File (*.stf)|*.stf|All Files (*.*)|*.*";
            spasiDialog.FilterIndex = 1;
            spasiDialog.RestoreDirectory = true;

            if (spasiDialog.ShowDialog() == DialogResult.OK)
            {
                ArrayList spasiVeze = new ArrayList();
                foreach (veza v in veze)
                    spasiVeze.Add(new spasi_otvori.Veza(v.p.ime, v.k.ime, v.funkcija));

                ArrayList spasiNodove = new ArrayList();
                foreach (state s in nodes)
                    spasiNodove.Add(new spasi_otvori.Node(s.Location, s.ime));

                ArrayList kraj = new ArrayList();
                foreach (state s in krajnji)
                    kraj.Add(s.Text);

                Stream streamWrite = File.Create(spasiDialog.FileName);
                BinaryFormatter binaryWrite = new BinaryFormatter();
                binaryWrite.Serialize(streamWrite, new spasi_otvori.zaSpasiti(spasiVeze, spasiNodove,pocetni.Text,kraj));
                streamWrite.Close();
            } 
        }

        private void otvoriToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("If you continue the current data will be lost!\nAre you shure?", "Are you shure?", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning)
              == DialogResult.Cancel)
                return;
            pobrisiEkran();
            preCrtaj();

            OpenFileDialog fdlg = new OpenFileDialog();
            fdlg.Title = "Open State file";
            fdlg.Filter = "State File (*.stf)|*.stf|All Files (*.*)|*.*";
            fdlg.FilterIndex = 1;
            fdlg.RestoreDirectory = true;
            if (fdlg.ShowDialog() == DialogResult.OK)
            {
                Stream streamRead = File.OpenRead(fdlg.FileName);
                BinaryFormatter binaryRead = new BinaryFormatter();
                spasi_otvori.zaSpasiti zaOtvoriti = (spasi_otvori.zaSpasiti)binaryRead.Deserialize(streamRead);
                streamRead.Close();

                foreach (spasi_otvori.Node s in zaOtvoriti.sNodovi)
                {
                    state novi = dodajState(s.lokacija.X, s.lokacija.Y);


                    if (s.ime == zaOtvoriti.pocetni)
                    {
                        if (pocetni != null)
                            pocetni.Image = global::stateHepek.Properties.Resources.state;
                        novi.Image = global::stateHepek.Properties.Resources.pocetni;
                        pocetni = novi;
                    }
                    foreach (string sk in zaOtvoriti.krajnji)
                        if (s.ime == sk)
                        {
                            novi.Image = global::stateHepek.Properties.Resources.kraj;
                            krajnji.Add(novi);
                        }
                }
                foreach (spasi_otvori.Veza v in zaOtvoriti.sVeze)
                {
                    state p = null, k = null;
                    foreach (state s in nodes)
                    {
                        if (s.ime == v.p) p = s;
                        if (s.ime == v.k) k = s;
                        if (p != null && k != null) break;
                    }
                    dodajVezu(p, k, v.funkcija);
                }
                preCrtaj();

            }


        }

        void printDoc_PrintPage(object sender, PrintPageEventArgs e)
        {
            Point ulCorner = new Point(100, 100);
            e.Graphics.DrawImage(zaPrint, ulCorner);
            
        }

        private void odstampajToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Graphics mg = this.CreateGraphics();
            Size s = this.Size;
            zaPrint = new Bitmap(s.Width, s.Height, mg);
            Graphics G = Graphics.FromImage(zaPrint);
            G.CopyFromScreen(this.Location.X, this.Location.Y, 0, 0, s);

            PrintDocument printDoc = new PrintDocument();
            printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage);
            PrintDialog dlg = new PrintDialog();

            dlg.Document = printDoc;

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                printDoc.Print();
            }

        }

        private void izadjiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void podloga_MouseClick(object sender, MouseEventArgs e)
        {
            podloga.ContextMenuStrip = null;
            if (tool == 0)
            {
                bool nadjena = false;
                Point[] selekcija;
                float px , py, kx, ky;

                foreach (veza v in veze)
                {
                    px = v.p.Location.X; py = v.p.Location.Y;
                    kx = v.k.Location.X; ky = v.k.Location.Y;
                    selekcija = new Point[]{
                         new Point(Convert.ToInt32(px+22), Convert.ToInt32(py+22-10)),
                         new Point(Convert.ToInt32(px+22), Convert.ToInt32(py+22+10)),
                         new Point(Convert.ToInt32(kx+22), Convert.ToInt32(ky+22+10)),
                         new Point(Convert.ToInt32(kx+22), Convert.ToInt32(ky+22-10)),
                         new Point(Convert.ToInt32(px+22), Convert.ToInt32(py+22-10))};
                    if (TackaPoligon(e.Location,selekcija) == true ) {
                        markiraniLink = selekcija;
                        markiranaVeza = v;
                        nadjena = true;
                        break;
                    }
                }
                if (nadjena == true)
                {
                    if (e.Button == MouseButtons.Right)
                        izbornikLinija.Show(new Point(this.Location.X + e.Location.X+5, this.Location.Y + e.Location.Y+82));
                    preCrtaj();
                }
                else { markiraniLink = null; markiranaVeza = null; preCrtaj(); }
            }
        }

        private void podloga_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (tool == 0)
            {
                if (markiranaVeza !=null) { 
                    VezaVar f2 = new VezaVar();
                    string funk="";
                    f2.funkcije.Text= markiranaVeza.funkcija;
                    if (f2.ShowDialog() == DialogResult.OK)
                        funk = f2.funkcije.Text;

                    markiranaVeza.funkcija = funk;
                    preCrtaj();
                }
            }
        }

        private void finiteStateAutomataToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void toolStripLabel1_Click(object sender, EventArgs e)
        {

        }

        private void izbrisiOznakuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            krajnji.Remove(contextSender);
            contextSender.Image = global::stateHepek.Properties.Resources.state;
        }

        private void izbrisiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (contextSender == pocetni)
                pocetni = null;
            foreach (state s in krajnji.ToArray())
                if (contextSender == s) krajnji.Remove(s);
            foreach (veza v in veze.ToArray())
                if (v.k == contextSender || v.p == contextSender)
                    veze.Remove(v);
            contextSender.Dispose();
            preCrtaj();
        }

        private void izbrisiToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            veze.Remove(markiranaVeza);
            markiranaVeza = null;
            preCrtaj();
        }

        private void izbornikLinija_Closed(object sender, ToolStripDropDownClosedEventArgs e)
        {
            preCrtaj();
        }

        private void editujToolStripMenuItem_Click(object sender, EventArgs e)
        {
            podloga_MouseDoubleClick(this, null);
        }

        private void otvoriSimulacijuToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void otvoriSimulacijuToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            OpenFileDialog fdlg = new OpenFileDialog();
            fdlg.Title = "Open Simulation Script";
            fdlg.Filter = "Simulation Scripta (*.ss)|*.ss|All Files (*.*)|*.*";
            fdlg.FilterIndex = 1;
            fdlg.RestoreDirectory = true;
            if (fdlg.ShowDialog() == DialogResult.OK)
            {
                StreamReader  streamRead = new StreamReader(fdlg.FileName);
                scriptCode =  streamRead.ReadToEnd();
            }
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            ScriptEditor s = new ScriptEditor(this);
            s.Show();
        }

        private void editorSimulacijeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ScriptEditor s = new ScriptEditor(this);
            s.Show();
        }

        public void play_Click(object sender, EventArgs e)
        {
            if (scriptCode == null) { return; }
            paxScripter1.Run(RunMode.Run);
            if (paxScripter1.HasErrors)
                paxScripter1.Reset();
            
        }

        private void izbornik_Closed(object sender, ToolStripDropDownClosedEventArgs e)
        {
            preCrtaj();
        }

        private void preimenujToolStripMenuItem_Click(object sender, EventArgs e)
        {
            VezaVar f2 = new VezaVar();
            f2.Text = "Rename state";
            f2.funkcije.Text = contextSender.ime;
            if (f2.ShowDialog() == DialogResult.OK)
            {
                contextSender.ime = f2.funkcije.Text;
                contextSender.Text = f2.funkcije.Text;
            }
            preCrtaj();
        }

        private void pokreniToolStripMenuItem_Click(object sender, EventArgs e)
        {
            play_Click(this, null);
        }

        private void expandablePanel1_Click(object sender, EventArgs e)
        {

        }

        private void step_Click(object sender, EventArgs e)
        {

        }

        private void uTMGrafUKomanduToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (ulaz.Text == "")
            {
                MessageBox.Show("Please enter a collection");
                return;
            }
            tabela.Rows.Clear() ;
            tabela.Columns.Clear();

            string[] parametri = ulaz.Text.Split('|');
            string[] test = parametri[0].Split(',');

            tabela.Columns.Add("stat", "stat");
            foreach (String s in test)
                tabela.Columns.Add(s, s);

            konzola.Text +=  "c";
            int ok = 0;
            foreach (state s in nodes)
            {
                konzola.Text += "c";
                ArrayList red = new ArrayList();
                red.Add(s.ime);
                foreach (String klj in test)
                {
                    foreach (veza v in veze)
                    {
                        string[] linija;
                        if (v.funkcija.IndexOf("\n") != -1)
                            linija = v.funkcija.Split('\n');
                        else { linija = new string[1]; linija[0] =  v.funkcija; }
                        
                        foreach (String sl in linija)
                            if (sl.StartsWith(klj) && v.p == s)
                            {
                       
                                ok = 1;
                                String[] f = sl.Split('>', ',');
                                red.Add("(" + v.k.ime.Substring(1, 1) + "," + f[2] + "," + f[1] + ")");
                                String ns ="";
                                // PREPRAVITI
                                for (int z = 0; z < Convert.ToInt32(v.k.ime.Substring(1, 1)) ; z++) ns += "1";
                                konzola.Text = konzola.Text + "c"+ns+f[2]+f[1];
                            }
                    }
                    if (ok != 1 && klj != "stat") { red.Add("d"); konzola.Text = konzola.Text + "c0"; };
                    ok = 0;
                }
                string[] strArray = red.ToArray(typeof(string)) as string[];
                tabela.Rows.Add(strArray);
            }
            konzola.Text = konzola.Text + "ccc" + parametri[1]; 
            ispis.Expanded = true;
        }

        private void oProgramuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("SimCode v0.1 by Teo Eterovic");
        }

        private void tEstniToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }


    }
}